package com.devilvan.betrice.douban.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devilvan.betrice.common.BetriceResultCode;
import com.devilvan.betrice.common.BetriceResultVo;
import com.devilvan.betrice.douban.constant.DoubanCommentRankStar;
import com.devilvan.betrice.douban.dto.DoubanCommentDto;
import com.devilvan.betrice.douban.po.DoubanCommentPo;
import com.devilvan.betrice.douban.po.DoubanMovieTop250Po;
import com.devilvan.betrice.douban.service.DoubanCommentService;
import com.devilvan.betrice.douban.mapper.DoubanCommentMapper;
import com.devilvan.betrice.douban.repository.DoubanCommentRepository;
import com.devilvan.betrice.request.component.JsoupComponent;
import com.devilvan.betrice.util.UEmpty;
import com.devilvan.betrice.util.UCopy;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author Evad.Wu
 * @Description 豆瓣-短评表 业务逻辑类
 * @date 2022-12-14
 */
@Service
public class DoubanCommentServiceImpl extends ServiceImpl<DoubanCommentMapper, DoubanCommentPo> implements DoubanCommentService {
    private static final String COMMON_SUFFIX = "comments";
    private static final String PARAM_SUFFIX = "?status=P";

    @Resource(name = "jsoupComponent")
    private JsoupComponent jsoupComponent;

    @Resource(name = "doubanCommentRepository")
    private DoubanCommentRepository doubanCommentRepository;

    @Override
    public BetriceResultVo<DoubanCommentPo> doDoubanCommentRequest(DoubanMovieTop250Po doubanMovieTop250Po, Map<String, String> headers) {
        BetriceResultVo<DoubanCommentPo> betriceResultVo = new BetriceResultVo<>();
        Long pid = doubanMovieTop250Po.getPid();
        String detailUrl = doubanMovieTop250Po.getDetailUrl();
        String commonUrl = detailUrl + COMMON_SUFFIX + PARAM_SUFFIX;
        headers.put("referer", detailUrl);
        List<DoubanCommentDto> doubanCommentDtoList = new ArrayList<>();
        int count = 1;
        while (true) {
            Element body = jsoupComponent.getBody(commonUrl, headers);
            doubanCommentDtoList.addAll(this.doDoubanCommentParser(body, pid));
            String nextPage = body.selectFirst("div#comments>div#paginator>a.next").attr("href");
            if (UEmpty.isEmpty(nextPage) || count == 60) {
                break;
            }
            commonUrl = detailUrl + COMMON_SUFFIX + nextPage;
            headers.put("referer", commonUrl);
            if (count % 11 == 0) {
                this.saveUpdateBatch(doubanCommentDtoList);
                doubanCommentDtoList.clear();
            }
            count++;
        }
        try {
            this.saveUpdateBatch(doubanCommentDtoList);
            betriceResultVo.result(BetriceResultCode.SUCCESS_200, "操作成功！");
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.FAILED_500, "操作失败！");
        }
        return betriceResultVo;
    }

    /**
     * 豆瓣电影短评采集
     *
     * @param body 网页源码
     * @param pid  电影系统ID
     * @return 采集并封装的dto集合
     */
    private List<DoubanCommentDto> doDoubanCommentParser(Element body, Long pid) {
        Elements commentItemList = body.select("div#comments>div.comment-item");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<DoubanCommentDto> doubanCommentDtoList = new ArrayList<>();
        for (Element commentItem : commentItemList) {
            Long commentId = Long.valueOf(commentItem.attr("data-cid"));
            Element commentInfo = commentItem.selectFirst("div.comment>h3>span.comment-info");
            Element reviewerUrlName = commentInfo.selectFirst("a");
            String reviewerUrl = reviewerUrlName.attr("href");
            String name = reviewerUrlName.text();
            String isWatched = commentItem.selectFirst("div.comment > h3 > span.comment-info > span:nth-child(2)").text();
            boolean watchedStatus = "看过".equals(isWatched);
            String rankStarTitle = commentItem.selectFirst("span:nth-child(3)").attr("title");
            Integer rankStar = DoubanCommentRankStar.getStarByTitle(rankStarTitle);
            String commentTimeText = commentItem.selectFirst("div.comment > h3 > span.comment-info > span.comment-time").text();
            Date commentTime = null;
            try {
                commentTime = dateFormat.parse(commentTimeText);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            Integer voteCount = Integer.valueOf(commentItem.selectFirst("div.comment>h3>span.comment-vote>span").text());
            String content = commentItem.selectFirst("div.comment>p>span").text();
            DoubanCommentDto doubanCommentDto = new DoubanCommentDto();
            doubanCommentDto.setPid(pid);
            doubanCommentDto.setCommentId(commentId);
            doubanCommentDto.setReviewer(name);
            doubanCommentDto.setReviewerUrl(reviewerUrl);
            doubanCommentDto.setWatchedStatus(watchedStatus);
            doubanCommentDto.setRankStar(rankStar);
            doubanCommentDto.setCommentDate(commentTime);
            doubanCommentDto.setAffirm(voteCount);
            doubanCommentDto.setContent(content);
            doubanCommentDtoList.add(doubanCommentDto);
        }
        return doubanCommentDtoList;
    }

    @Override
    public DoubanCommentPo saveUpdate(DoubanCommentDto doubanCommentDto) {
        DoubanCommentPo doubanCommentPo = new DoubanCommentPo();
        UCopy.fullCopy(doubanCommentDto, doubanCommentPo);
        return doubanCommentRepository.saveAndFlush(doubanCommentPo);
    }

    @Override
    public List<DoubanCommentPo> saveUpdateBatch(List<DoubanCommentDto> list) {
        List<DoubanCommentPo> doubanCommentPoList = UCopy.fullCopyCollections(list, DoubanCommentPo.class);
        return doubanCommentRepository.saveAllAndFlush(doubanCommentPoList);
    }

}
